package com.gitee.wsl.text.predicate


//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

import com.gitee.wsl.func.predicate.Predicate
import com.gitee.wsl.text.predicate.CharMatcher.NamedFastMatcher
import com.gitee.wsl.test.Preconditions.checkArgument
import com.gitee.wsl.test.Preconditions.checkPositionIndex
import com.gitee.wsl.lang.bits.BitSet


/**
 * Determines a true or false value for any Java `char` value, just as [Predicate] does
 * for any [Object]. Also offers basic text processing methods based on this function.
 * Implementations are strongly encouraged to be side-effect-free and immutable.
 *
 *
 * Throughout the documentation of this class, the phrase "matching character" is used to mean
 * "any `char` value `c` for which `this.matches(c)` returns `true`".
 *
 *
 * **Warning:** This class deals only with `char` values, that is, [BMP characters](http://www.unicode.org/glossary/#BMP_character). It does not understand
 * [supplementary Unicode code
 * points](http://www.unicode.org/glossary/#supplementary_code_point) in the range `0x10000` to `0x10FFFF` which includes the majority of
 * assigned characters, including important CJK characters and emoji.
 *
 *
 * Supplementary characters are [encoded
 * into a `String` using surrogate pairs](https://docs.oracle.com/javase/8/docs/api/java/lang/Char.html#supplementary), and a `CharMatcher` treats these just as
 * two separate characters. [.countIn] counts each supplementary character as 2 `char`s.
 *
 *
 * For up-to-date Unicode character properties (digit, letter, etc.) and support for
 * supplementary code points, use ICU4J UCharacter and UnicodeSet (freeze() after building). For
 * basic text processing based on UnicodeSet use the ICU4J UnicodeSetSpanner.
 *
 *
 * Example usages:
 *
 * <pre>
 * String trimmed = [whitespace()][.whitespace].[trimFrom][.trimFrom](userInput);
 * if ([ascii()][.ascii].[matchesAllOf][.matchesAllOf](s)) { ... }</pre>
 *
 *
 * See the Guava User Guide article on [`CharMatcher`
](https://github.com/google/guava/wiki/StringsExplained#charmatcher) * .
 *
 * @author Kevin Bourrillion
 * @since 1.0
 */

abstract class CharMatcher () : Predicate<Char> {
    override fun test(t: Char): Boolean {
        return matches(t)
    }

    // Abstract methods
    /** Determines a true or false value for the given character.  */
    abstract fun matches(c: Char): Boolean

    // Non-static factories
    /** Returns a matcher that matches any character not matched by this matcher.  */ // @Override under Java 8 but not under Java 7
    override fun negate(): CharMatcher {
        return Negated(this)
    }

    /**
     * Returns a matcher that matches any character matched by both this matcher and `other`.
     */
    open fun and(other: CharMatcher): CharMatcher {
        return And(this, other)
    }

    /**
     * Returns a matcher that matches any character matched by either this matcher or `other`.
     */
    open fun or(other: CharMatcher): CharMatcher {
        return Or(this, other)
    }

    /**
     * Returns a `char` matcher functionally equivalent to this one, but which may be faster to
     * query than the original; your mileage may vary. Precomputation takes time and is likely to be
     * worthwhile only if the precomputed matcher is queried many thousands of times.
     *
     *
     * This method has no effect (returns `this`) when called in GWT: it's unclear whether a
     * precomputed matcher is faster, but it certainly consumes more memory, which doesn't seem like a
     * worthwhile tradeoff in a browser.
     */
    open fun precomputed(): CharMatcher {
        return precomputedInternal()
    }

    /**
     * This is the actual implementation of [.precomputed], but we bounce calls through a method
     * on [Platform] so that we can have different behavior in GWT.
     *
     *
     * This implementation tries to be smart in a number of ways. It recognizes cases where the
     * negation is cheaper to precompute than the matcher itself; it tries to build small hash tables
     * for matchers that only match a few characters, and so on. In the worst-case scenario, it
     * constructs an eight-kilobyte bit array and queries that. In many situations this produces a
     * matcher which is faster to query than the original.
     */

    fun  precomputedInternal(): CharMatcher {
        val table = BitSet()
        setBits(table)
        val totalCharacters = table.cardinality()
        return if (totalCharacters * 2 <= DISTINCT_CHARS) {
            precomputedPositive(totalCharacters, table, toString())
        } else {
            // TODO(lowasser): is it worth it to worry about the last character of large matchers?
            table.flip(Char.MIN_VALUE.code, Char.MAX_VALUE.code + 1)
            val negatedCharacters = DISTINCT_CHARS - totalCharacters
            val suffix = ".negate()"
            val description = toString()
            val negatedDescription = if (description.endsWith(suffix)) description.substring(
                0,
                description.length - suffix.length
            ) else description + suffix
            object : NegatedFastMatcher(
                precomputedPositive(negatedCharacters, table, negatedDescription)
            ) {
                override fun toString(): String {
                    return description
                }
            }
        }
    }

    /** Sets bits in `table` matched by this matcher.  */

    open fun setBits(table: BitSet) {
        var c = Char.MAX_VALUE.code
        while (c >= Char.MIN_VALUE.code) {
            if (matches(c.toChar())) {
                table.set(c)
            }
            c--
        }
    }
    // Text processing routines
    /**
     * Returns `true` if a character sequence contains at least one matching BMP character.
     * Equivalent to `!matchesNoneOf(sequence)`.
     *
     *
     * The default implementation iterates over the sequence, invoking [.matches] for each
     * character, until this returns `true` or the end is reached.
     *
     * @param sequence the character sequence to examine, possibly empty
     * @return `true` if this matcher matches at least one character in the sequence
     * @since 8.0
     */
    fun matchesAnyOf(sequence: CharSequence): Boolean {
        return !matchesNoneOf(sequence)
    }

    /**
     * Returns `true` if a character sequence contains only matching BMP characters.
     *
     *
     * The default implementation iterates over the sequence, invoking [.matches] for each
     * character, until this returns `false` or the end is reached.
     *
     * @param sequence the character sequence to examine, possibly empty
     * @return `true` if this matcher matches every character in the sequence, including when
     * the sequence is empty
     */
    open fun matchesAllOf(sequence: CharSequence): Boolean {
        for (i in sequence.length - 1 downTo 0) {
            if (!matches(sequence[i])) {
                return false
            }
        }
        return true
    }

    /**
     * Returns `true` if a character sequence contains no matching BMP characters. Equivalent to
     * `!matchesAnyOf(sequence)`.
     *
     *
     * The default implementation iterates over the sequence, invoking [.matches] for each
     * character, until this returns `true` or the end is reached.
     *
     * @param sequence the character sequence to examine, possibly empty
     * @return `true` if this matcher matches no characters in the sequence, including when the
     * sequence is empty
     */
    open fun matchesNoneOf(sequence: CharSequence): Boolean {
        return indexIn(sequence) == -1
    }
    /**
     * Returns the index of the first matching BMP character in a character sequence, starting from a
     * given position, or `-1` if no character matches after that position.
     *
     *
     * The default implementation iterates over the sequence in forward order, beginning at `start`, calling [.matches] for each character.
     *
     * @param sequence the character sequence to examine
     * @param start the first index to examine; must be nonnegative and no greater than `sequence.length()`
     * @return the index of the first matching character, guaranteed to be no less than `start`,
     * or `-1` if no character matches
     * @throws IndexOutOfBoundsException if start is negative or greater than `sequence.length()`
     */
     open fun indexIn(sequence: CharSequence): Int {
        return if (sequence.isEmpty()) -1 else 0
    }

    /**
     * Returns the index of the first matching BMP character in a character sequence, or `-1` if
     * no matching character is present.
     *
     *
     * The default implementation iterates over the sequence in forward order calling [ ][.matches] for each character.
     *
     * @param sequence the character sequence to examine from the beginning
     * @return an index, or `-1` if no character matches
     */
    open fun indexIn(sequence: CharSequence, start: Int = 0): Int {
        val length = sequence.length
       checkPositionIndex(start, length)
        for (i in start until length) {
            if (matches(sequence[i])) {
                return i
            }
        }
        return -1
    }

    /**
     * Returns the index of the last matching BMP character in a character sequence, or `-1` if
     * no matching character is present.
     *
     *
     * The default implementation iterates over the sequence in reverse order calling [ ][.matches] for each character.
     *
     * @param sequence the character sequence to examine from the end
     * @return an index, or `-1` if no character matches
     */
    open fun lastIndexIn(sequence: CharSequence): Int {
        for (i in sequence.length - 1 downTo 0) {
            if (matches(sequence[i])) {
                return i
            }
        }
        return -1
    }

    /**
     * Returns the number of matching `char`s found in a character sequence.
     *
     *
     * Counts 2 per supplementary character, such as for [.whitespace]().[.negate]().
     */
    open fun countIn(sequence: CharSequence): Int {
        var count = 0
        for (element in sequence) {
            if (matches(element)) {
                count++
            }
        }
        return count
    }

    /**
     * Returns a string containing all non-matching characters of a character sequence, in order. For
     * example:
     *
     * <pre>`CharMatcher.is('a').removeFrom("bazaar")
    `</pre> *
     *
     * ... returns `"bzr"`.
     */
    open fun removeFrom(sequence: CharSequence): String {
        val string = sequence.toString()
        var pos = indexIn(string)
        if (pos == -1) {
            return string
        }
        val chars = string.toCharArray()
        var spread = 1

        // This unusual loop comes from extensive benchmarking
        OUT@ while (true) {
            pos++
            while (true) {
                if (pos == chars.size) {
                    break@OUT
                }
                if (matches(chars[pos])) {
                    break
                }
                chars[pos - spread] = chars[pos]
                pos++
            }
            spread++
        }
        return chars.concatToString(0, 0 + (pos - spread))
    }

    /**
     * Returns a string containing all matching BMP characters of a character sequence, in order. For
     * example:
     *
     * <pre>`CharMatcher.is('a').retainFrom("bazaar")
    `</pre> *
     *
     * ... returns `"aaa"`.
     */
    fun retainFrom(sequence: CharSequence): String {
        return negate().removeFrom(sequence)
    }

    /**
     * Returns a string copy of the input character sequence, with each matching BMP character
     * replaced by a given replacement character. For example:
     *
     * <pre>`CharMatcher.is('a').replaceFrom("radar", 'o')
    `</pre> *
     *
     * ... returns `"rodor"`.
     *
     *
     * The default implementation uses [.indexIn] to find the first matching
     * character, then iterates the remainder of the sequence calling [.matches] for each
     * character.
     *
     * @param sequence the character sequence to replace matching characters in
     * @param replacement the character to append to the result string in place of each matching
     * character in `sequence`
     * @return the new string
     */
    open fun replaceFrom(sequence: CharSequence, replacement: Char): String {
        val string = sequence.toString()
        val pos = indexIn(string)
        if (pos == -1) {
            return string
        }
        val chars = string.toCharArray()
        chars[pos] = replacement
        for (i in pos + 1 until chars.size) {
            if (matches(chars[i])) {
                chars[i] = replacement
            }
        }
        return chars.concatToString()
    }

    /**
     * Returns a string copy of the input character sequence, with each matching BMP character
     * replaced by a given replacement sequence. For example:
     *
     * <pre>`CharMatcher.is('a').replaceFrom("yaha", "oo")
    `</pre> *
     *
     * ... returns `"yoohoo"`.
     *
     *
     * **Note:** If the replacement is a fixed string with only one character, you are better
     * off calling [.replaceFrom] directly.
     *
     * @param sequence the character sequence to replace matching characters in
     * @param replacement the characters to append to the result string in place of each matching
     * character in `sequence`
     * @return the new string
     */
    open fun replaceFrom(sequence: CharSequence, replacement: CharSequence): String {
        val replacementLen = replacement.length
        if (replacementLen == 0) {
            return removeFrom(sequence)
        }
        if (replacementLen == 1) {
            return replaceFrom(sequence, replacement[0])
        }
        val string = sequence.toString()
        var pos = indexIn(string)
        if (pos == -1) {
            return string
        }
        val len = string.length
        val buf = StringBuilder(len * 3 / 2 + 16)
        var oldpos = 0
        do {
            buf.append(string, oldpos, pos)
            buf.append(replacement)
            oldpos = pos + 1
            pos = indexIn(string, oldpos)
        } while (pos != -1)
        buf.append(string, oldpos, len)
        return buf.toString()
    }

    /**
     * Returns a substring of the input character sequence that omits all matching BMP characters from
     * the beginning and from the end of the string. For example:
     *
     * <pre>`CharMatcher.anyOf("ab").trimFrom("abacatbab")
    `</pre> *
     *
     * ... returns `"cat"`.
     *
     *
     * Note that:
     *
     * <pre>`CharMatcher.inRange('\0', ' ').trimFrom(str)
    `</pre> *
     *
     * ... is equivalent to [String.trim].
     */
    open fun trimFrom(sequence: CharSequence): String {
        val len = sequence.length
        var first: Int = 0
        while (first < len) {
            if (!matches(sequence[first])) {
                break
            }
            first++
        }
        var last: Int = len - 1
        while (last > first) {
            if (!matches(sequence[last])) {
                break
            }
            last--
        }
        return sequence.subSequence(first, last + 1).toString()
    }

    /**
     * Returns a substring of the input character sequence that omits all matching BMP characters from
     * the beginning of the string. For example:
     *
     * <pre>`CharMatcher.anyOf("ab").trimLeadingFrom("abacatbab")
    `</pre> *
     *
     * ... returns `"catbab"`.
     */
    open fun trimLeadingFrom(sequence: CharSequence): String {
        val len = sequence.length
        for (first in 0 until len) {
            if (!matches(sequence[first])) {
                return sequence.subSequence(first, len).toString()
            }
        }
        return ""
    }

    /**
     * Returns a substring of the input character sequence that omits all matching BMP characters from
     * the end of the string. For example:
     *
     * <pre>`CharMatcher.anyOf("ab").trimTrailingFrom("abacatbab")
    `</pre> *
     *
     * ... returns `"abacat"`.
     */
    open fun trimTrailingFrom(sequence: CharSequence): String {
        val len = sequence.length
        for (last in len - 1 downTo 0) {
            if (!matches(sequence[last])) {
                return sequence.subSequence(0, last + 1).toString()
            }
        }
        return ""
    }

    /**
     * Returns a string copy of the input character sequence, with each group of consecutive matching
     * BMP characters replaced by a single replacement character. For example:
     *
     * <pre>`CharMatcher.anyOf("eko").collapseFrom("bookkeeper", '-')
    `</pre> *
     *
     * ... returns `"b-p-r"`.
     *
     *
     * The default implementation uses [.indexIn] to find the first matching
     * character, then iterates the remainder of the sequence calling [.matches] for each
     * character.
     *
     * @param sequence the character sequence to replace matching groups of characters in
     * @param replacement the character to append to the result string in place of each group of
     * matching characters in `sequence`
     * @return the new string
     */
    open fun collapseFrom(sequence: CharSequence, replacement: Char): String {
        // This implementation avoids unnecessary allocation.
        val len = sequence.length
        var i = 0
        while (i < len) {
            val c = sequence[i]
            if (matches(c)) {
                if (c == replacement && (i == len - 1 || !matches(sequence[i + 1]))) {
                    // a no-op replacement
                    i++
                } else {
                    val builder = StringBuilder(len).append(sequence, 0, i).append(replacement)
                    return finishCollapseFrom(sequence, i + 1, len, replacement, builder, true)
                }
            }
            i++
        }
        // no replacement needed
        return sequence.toString()
    }

    /**
     * Collapses groups of matching characters exactly as [.collapseFrom] does, except that
     * groups of matching BMP characters at the start or end of the sequence are removed without
     * replacement.
     */
    fun trimAndCollapseFrom(sequence: CharSequence, replacement: Char): String {
        // This implementation avoids unnecessary allocation.
        val len = sequence.length
        var first = 0
        var last = len - 1
        while (first < len && matches(sequence[first])) {
            first++
        }
        while (last > first && matches(sequence[last])) {
            last--
        }
        return if (first == 0 && last == len - 1) collapseFrom(
            sequence,
            replacement
        ) else finishCollapseFrom(
            sequence, first, last + 1, replacement, StringBuilder(last + 1 - first), false
        )
    }

    private fun finishCollapseFrom(
        sequence: CharSequence,
        start: Int,
        end: Int,
        replacement: Char,
        builder: StringBuilder,
        inMatchingGroup: Boolean
    ): String {
        var inMatchingGroup = inMatchingGroup
        for (i in start until end) {
            val c = sequence[i]
            if (matches(c)) {
                if (!inMatchingGroup) {
                    builder.append(replacement)
                    inMatchingGroup = true
                }
            } else {
                builder.append(c)
                inMatchingGroup = false
            }
        }
        return builder.toString()
    }



    /**
     * Returns a string representation of this `CharMatcher`, such as `CharMatcher.or(WHITESPACE, JAVA_DIGIT)`.
     */
    override fun toString(): String {
        return super.toString()
    }

    // Fast matchers
    /** A matcher for which precomputation will not yield any significant benefit.  */
     abstract class FastMatcher : CharMatcher() {
        override fun precomputed(): CharMatcher {
            return this
        }

        override fun negate(): CharMatcher {
            return NegatedFastMatcher(this)
        }
    }

    /** [FastMatcher] which overrides `toString()` with a custom name.  */
     abstract class NamedFastMatcher(val description: String) : FastMatcher() {

        override fun toString(): String {
            return description
        }
    }

    /** Negation of a [FastMatcher].  */
    private open class NegatedFastMatcher (original: CharMatcher) : Negated(original) {
        override fun precomputed(): CharMatcher {
            return this
        }
    }

    /** Fast matcher using a [BitSet] table of matching characters.  */
   
     // used only from other GwtIncompatible code

    private class BitSetMatcher(table: BitSet, description: String) : NamedFastMatcher(description) {
        private val table: BitSet

        init {
            var table = table
            if (table.length() + Long.SIZE_BITS < table.length()) {
                table = table.clone() 
                // If only we could actually call FixedBitSet.trimToSize() ourselves...
            }
            this.table = table
        }

        override fun matches(c: Char): Boolean {
            return table[c.code]
        }

        override fun setBits(table: BitSet) {
            table.or(this.table)
        }
    }
    // Static constant implementation classes
    /** Implementation of [.any].  */
    private class Any() : NamedFastMatcher("CharMatcher.any()") {
        override fun matches(c: Char): Boolean {
            return true
        }

       override fun indexIn(sequence: CharSequence): Int {
            return if (sequence.isEmpty()) -1 else 0
        }

        override fun indexIn(sequence: CharSequence, start: Int): Int {
            val length = sequence.length
            checkPositionIndex(start, length)
            return if (start == length) -1 else start
        }

        override fun lastIndexIn(sequence: CharSequence): Int {
            return sequence.length - 1
        }

        override fun matchesAllOf(sequence: CharSequence): Boolean {
            return true
        }

        override fun matchesNoneOf(sequence: CharSequence): Boolean {
            return sequence.isEmpty()
        }

        override fun removeFrom(sequence: CharSequence): String {
            return ""
        }

        override fun replaceFrom(sequence: CharSequence, replacement: Char): String {
            val array = CharArray(sequence.length){replacement}
            return array.concatToString()
        }

        override fun replaceFrom(sequence: CharSequence, replacement: CharSequence): String {
            val result = StringBuilder(sequence.length * replacement.length)
            for (i in sequence.indices) {
                result.append(replacement)
            }
            return result.toString()
        }

        override fun collapseFrom(sequence: CharSequence, replacement: Char): String {
            return if (sequence.isEmpty()) "" else replacement.toString()
        }

        override fun trimFrom(sequence: CharSequence): String {
            return ""
        }

        override fun countIn(sequence: CharSequence): Int {
            return sequence.length
        }

        override fun and(other: CharMatcher): CharMatcher {
            return other
        }

        override fun or(other: CharMatcher): CharMatcher {
            return this
        }

        override fun negate(): CharMatcher {
            return none()
        }

        companion object {
            val INSTANCE: CharMatcher = Any()
        }
    }

    /** Implementation of [.none].  */
    private class None () : NamedFastMatcher("CharMatcher.none()") {
        override fun matches(c: Char): Boolean {
            return false
        }

        override fun indexIn(sequence: CharSequence): Int {
            return -1
        }

        override fun indexIn(sequence: CharSequence, start: Int): Int {
            val length = sequence.length
            checkPositionIndex(start, length)
            return -1
        }

        override fun lastIndexIn(sequence: CharSequence): Int {

            return -1
        }

        override fun matchesAllOf(sequence: CharSequence): Boolean {
            return sequence.isEmpty()
        }

        override fun matchesNoneOf(sequence: CharSequence): Boolean {
            return true
        }

        override fun removeFrom(sequence: CharSequence): String {
            return sequence.toString()
        }

        override fun replaceFrom(sequence: CharSequence, replacement: Char): String {
            return sequence.toString()
        }

        override fun replaceFrom(sequence: CharSequence, replacement: CharSequence): String {
            return sequence.toString()
        }

        override fun collapseFrom(sequence: CharSequence, replacement: Char): String {
            return sequence.toString()
        }

        override fun trimFrom(sequence: CharSequence): String {
            return sequence.toString()
        }

        override fun trimLeadingFrom(sequence: CharSequence): String {
            return sequence.toString()
        }

        override fun trimTrailingFrom(sequence: CharSequence): String {
            return sequence.toString()
        }

        override fun countIn(sequence: CharSequence): Int {
            return 0
        }

        override fun and(other: CharMatcher): CharMatcher {
            return this
        }

        override fun or(other: CharMatcher): CharMatcher {
            return other
        }

        override fun negate(): CharMatcher {
            return any()
        }

        companion object {
            val INSTANCE: CharMatcher = None()
        }
    }

    /** Implementation of [.whitespace].  */
    internal class Whitespace : NamedFastMatcher("CharMatcher.whitespace()") {
        override fun matches(c: Char): Boolean {
            return TABLE[MULTIPLIER * c.code ushr SHIFT] == c
        }

       
         // used only from other GwtIncompatible code
        override fun setBits(table: BitSet) {
            for (element in TABLE) {
                table.set(element.code)
            }
        }

        companion object {
            // TABLE is a precomputed hashset of whitespace characters. MULTIPLIER serves as a hash function
            // whose key property is that it maps 25 characters into the 32-slot table without collision.
            // Basically this is an opportunistic fast implementation as opposed to "good code". For most
            // other use-cases, the reduction in readability isn't worth it.
            const val TABLE = ("\u2002\u3000\r\u0085\u200A\u2005\u2000\u3000"
                    + "\u2029\u000B\u3000\u2008\u2003\u205F\u3000\u1680"
                    + "\u0009\u0020\u2006\u2001\u202F\u00A0\u000C\u2009"
                    + "\u3000\u2004\u3000\u3000\u2028\n\u2007\u3000")
            const val MULTIPLIER = 1682554634
            val SHIFT=(TABLE.length - 1).countLeadingZeroBits()
            //val SHIFT = Int.numberOfLeadingZeros(TABLE.length - 1)
            val INSTANCE: CharMatcher = Whitespace()
        }
    }

    /** Implementation of [.breakingWhitespace].  */
    private class BreakingWhitespace : CharMatcher() {
        override fun matches(c: Char): Boolean {
            return when (c) {
                '\t', '\n', '\u000b', '\u000c', '\r', ' ', '\u0085', '\u1680', '\u2028', '\u2029', '\u205f', '\u3000' -> true
                '\u2007' -> false
                else -> c in '\u2000'..'\u200a'
            }
        }

        override fun toString(): String {
            return "CharMatcher.breakingWhitespace()"
        }

        companion object {
            val INSTANCE: CharMatcher = BreakingWhitespace()
        }
    }

    /** Implementation of [.ascii].  */
    private class Ascii () : NamedFastMatcher("CharMatcher.ascii()") {
        override fun matches(c: Char): Boolean {
            return c <= '\u007f'
        }

        companion object {
            val INSTANCE: CharMatcher = Ascii()
        }
    }

    /** Implementation that matches characters that fall within multiple ranges.  */
    private open class RangesMatcher  (
        private val description: String,
        private val rangeStarts: CharArray,
        private val rangeEnds: CharArray
    ) :
        CharMatcher() {
        init {
           checkArgument(rangeStarts.size == rangeEnds.size)
            for (i in rangeStarts.indices) {
                checkArgument(rangeStarts[i] <= rangeEnds[i])
                if (i + 1 < rangeStarts.size) {
                   checkArgument(rangeEnds[i] < rangeStarts[i + 1])
                }
            }
        }

        override fun matches(c: Char): Boolean {
            var index = rangeStarts.indexOf(c)
            return if (index >= 0) {
                true
            } else {
                index = index.inv() - 1
                index >= 0 && c <= rangeEnds[index]
            }
        }

        override fun toString(): String {
            return description
        }
    }

    /** Implementation of [.digit].  */
    private class Digit( description: String,
                         rangeStarts: CharArray,
                         rangeEnds: CharArray) : RangesMatcher(description, rangeStarts, rangeEnds) {
        // Plug the following UnicodeSet pattern into
        // https://unicode.org/cldr/utility/list-unicodeset.jsp
        // [[:Nd:]&[:nv=0:]&[\u0000-\uFFFF]]
        // and get the zeroes from there.
        // Must be in ascending order.

        companion object{
            private const val ZEROES = ("0\u0660\u06f0\u07c0\u0966\u09e6\u0a66\u0ae6\u0b66\u0be6\u0c66\u0ce6\u0d66\u0de6"
                    + "\u0e50\u0ed0\u0f20\u1040\u1090\u17e0\u1810\u1946\u19d0\u1a80\u1a90\u1b50\u1bb0"
                    + "\u1c40\u1c50\ua620\ua8d0\ua900\ua9d0\ua9f0\uaa50\uabf0\uff10")

            private fun zeroes(): CharArray {
                return ZEROES.toCharArray()
            }

            private fun nines(): CharArray {
                val nines = CharArray(ZEROES.length)
                for (i in ZEROES.indices) {
                    nines[i] = (ZEROES[i].code + 9).toChar()
                }
                return nines
            }

            val INSTANCE: CharMatcher = Digit("CharMatcher.digit()", zeroes(), nines())
        }
    }

    /** Implementation of [.javaDigit].  */
    private class JavaDigit : CharMatcher() {
        override fun matches(c: Char): Boolean {
            return c.isDigit()
        }

        override fun toString(): String {
            return "CharMatcher.javaDigit()"
        }

        companion object {
            val INSTANCE: CharMatcher = JavaDigit()
        }
    }

    /** Implementation of [.javaLetter].  */
    private class JavaLetter : CharMatcher() {
        override fun matches(c: Char): Boolean {
            return c.isLetter()
        }

        override fun toString(): String {
            return "CharMatcher.javaLetter()"
        }

        companion object {
            val INSTANCE: CharMatcher = JavaLetter()
        }
    }

    /** Implementation of [.javaLetterOrDigit].  */
    private class JavaLetterOrDigit : CharMatcher() {
        override fun matches(c: Char): Boolean {
            return c.isLetterOrDigit()
        }

        override fun toString(): String {
            return "CharMatcher.javaLetterOrDigit()"
        }

        companion object {
            val INSTANCE: CharMatcher = JavaLetterOrDigit()
        }
    }

    /** Implementation of [.javaUpperCase].  */
    private class JavaUpperCase : CharMatcher() {
        override fun matches(c: Char): Boolean {
            return c.isUpperCase()
        }

        override fun toString(): String {
            return "CharMatcher.javaUpperCase()"
        }

        companion object {
            val INSTANCE: CharMatcher = JavaUpperCase()
        }
    }

    /** Implementation of [.javaLowerCase].  */
    private class JavaLowerCase : CharMatcher() {
        override fun matches(c: Char): Boolean {
            return c.isLowerCase()
        }

        override fun toString(): String {
            return "CharMatcher.javaLowerCase()"
        }

        companion object {
            val INSTANCE: CharMatcher = JavaLowerCase()
        }
    }

    /** Implementation of [.javaIsoControl].  */
    private class JavaIsoControl private constructor() :
        NamedFastMatcher("CharMatcher.javaIsoControl()") {
        override fun matches(c: Char): Boolean {
            return c <= '\u001f' || c in '\u007f'..'\u009f'
        }

        companion object {
            val INSTANCE: CharMatcher = JavaIsoControl()
        }
    }

    /** Implementation of [.invisible].  */
    private class Invisible( description: String,
                              rangeStarts: CharArray,
                              rangeEnds: CharArray) : RangesMatcher(description, rangeStarts, rangeEnds) {

        companion object{
            // Plug the following UnicodeSet pattern into
            // https://unicode.org/cldr/utility/list-unicodeset.jsp
            // [[[:Zs:][:Zl:][:Zp:][:Cc:][:Cf:][:Cs:][:Co:]]&[\u0000-\uFFFF]]
            // with the "Abbreviate" option, and get the ranges from there.
            private const val RANGE_STARTS =
                ("\u0000\u007f\u00ad\u0600\u061c\u06dd\u070f\u0890\u08e2\u1680\u180e\u2000\u2028\u205f\u2066"
                        + "\u3000\ud800\ufeff\ufff9")
            private const val RANGE_ENDS = ( // inclusive ends
                    "\u0020\u00a0\u00ad\u0605\u061c\u06dd\u070f\u0891\u08e2\u1680\u180e\u200f\u202f\u2064\u206f"
                            + "\u3000\uf8ff\ufeff\ufffb")
            val INSTANCE: CharMatcher = Invisible("CharMatcher.invisible()", RANGE_STARTS.toCharArray(), RANGE_ENDS.toCharArray())
        }
    }

    /** Implementation of [.singleWidth].  */
    private class SingleWidth(description: String,
                              rangeStarts: CharArray,
                              rangeEnds: CharArray) : RangesMatcher(description, rangeStarts, rangeEnds) {

        companion object{
            val INSTANCE: CharMatcher = SingleWidth("CharMatcher.singleWidth()",
                "\u0000\u05be\u05d0\u05f3\u0600\u0750\u0e00\u1e00\u2100\ufb50\ufe70\uff61".toCharArray(),
                "\u04f9\u05be\u05ea\u05f4\u06ff\u077f\u0e7f\u20af\u213a\ufdff\ufeff\uffdc".toCharArray())
        }
    }
    // Non-static factory implementation classes
    /** Implementation of [.negate].  */
    private open class Negated  constructor(val original: CharMatcher) : CharMatcher() {

        override fun matches(c: Char): Boolean {
            return !original.matches(c)
        }

        override fun matchesAllOf(sequence: CharSequence): Boolean {
            return original.matchesNoneOf(sequence)
        }

        override fun matchesNoneOf(sequence: CharSequence): Boolean {
            return original.matchesAllOf(sequence)
        }

        override fun countIn(sequence: CharSequence): Int {
            return sequence.length - original.countIn(sequence)
        }

       
         // used only from other GwtIncompatible code
        override fun setBits(table: BitSet) {
            val tmp = BitSet()
            original.setBits(tmp)
            tmp.flip(Char.MIN_VALUE.code, Char.MAX_VALUE.code + 1)
            table.or(tmp)
        }

        override fun negate(): CharMatcher {
            return original
        }

        override fun toString(): String {
            return "$original.negate()"
        }
    }

    /** Implementation of [.and].  */
    private class And  constructor(val first: CharMatcher,
                                   val second: CharMatcher
    ) : CharMatcher() {

        override fun matches(c: Char): Boolean {
            return first.matches(c) && second.matches(c)
        }

       
         // used only from other GwtIncompatible code
        override fun setBits(table: BitSet) {
            val tmp1 = BitSet()
            first.setBits(tmp1)
            val tmp2 = BitSet()
            second.setBits(tmp2)
            tmp1.and(tmp2)
            table.or(tmp1)
        }

        override fun toString(): String {
            return "CharMatcher.and($first, $second)"
        }
    }

    /** Implementation of [.or].  */
    private class Or(val first: CharMatcher,
                     val second: CharMatcher
    ) : CharMatcher() {

        override fun setBits(table: BitSet) {
            first.setBits(table)
            second.setBits(table)
        }

        override fun matches(c: Char): Boolean {
            return first.matches(c) || second.matches(c)
        }

        override fun toString(): String {
            return "CharMatcher.or($first, $second)"
        }
    }
    // Static factory implementations
    /** Implementation of [.is].  */
    private class Is (private val match: Char) : FastMatcher() {
        override fun matches(c: Char): Boolean {
            return c == match
        }

        override fun replaceFrom(sequence: CharSequence, replacement: Char): String {
            return sequence.toString().replace(match, replacement)
        }

        override fun and(other: CharMatcher): CharMatcher {
            return if (other.matches(match)) this else none()
        }

        override fun or(other: CharMatcher): CharMatcher {
            return if (other.matches(match)) other else super.or(other)
        }

        override fun negate(): CharMatcher {
            return isNot(match)
        }

       
         // used only from other GwtIncompatible code
        override fun setBits(table: BitSet) {
            table.set(match.code)
        }

        override fun toString(): String {
            return "CharMatcher.is('" + showCharacter(match) + "')"
        }
    }

    /** Implementation of [.isNot].  */
    private class IsNot(private val match: Char) : FastMatcher() {
        override fun matches(c: Char): Boolean {
            return c != match
        }

        override fun and(other: CharMatcher): CharMatcher {
            return if (other.matches(match)) super.and(other) else other
        }

        override fun or(other: CharMatcher): CharMatcher {
            return if (other.matches(match)) any() else this
        }

       
         // used only from other GwtIncompatible code
        override fun setBits(table: BitSet) {
            table.set(0,match.code)
            table.set(match.code + 1, Char.MAX_VALUE.code + 1)
            //table[0] = match.code
            //table[match.code + 1] = Char.MAX_VALUE.code + 1
        }

        override fun negate(): CharMatcher {
            return Is(match)
        }

        override fun toString(): String {
            return "CharMatcher.isNot('" + showCharacter(match) + "')"
        }
    }

    /** Implementation of [.anyOf] for exactly two characters.  */
    private class IsEither internal constructor(
        private val match1: Char,
        private val match2: Char
    ) : FastMatcher() {
        override fun matches(c: Char): Boolean {
            return c == match1 || c == match2
        }

       
         // used only from other GwtIncompatible code
        override fun setBits(table: BitSet) {
            table.set(match1.code)
            table.set(match2.code)
        }

        override fun toString(): String {
            return "CharMatcher.anyOf(\"" + showCharacter(match1) + showCharacter(
                match2
            ) + "\")"
        }
    }

    /** Implementation of [.anyOf] for three or more characters.  */
    private class AnyOf(chars: CharSequence) : CharMatcher() {
        private val chars: CharArray = chars.toString().toCharArray().sortedArray()


        override fun matches(c: Char): Boolean {
            return chars.indexOf(c) >= 0
        }

        override fun  // used only from other GwtIncompatible code
                setBits(table: BitSet) {
            for (c in chars) {
                table.set(c.code)
            }
        }

        override fun toString(): String {
            val description = StringBuilder("CharMatcher.anyOf(\"")
            for (c in chars) {
                description.append(showCharacter(c))
            }
            description.append("\")")
            return description.toString()
        }
    }

    /** Implementation of [.inRange].  */
    private class InRange(startInclusive: Char, endInclusive: Char) :
        FastMatcher() {
        private val startInclusive: Char
        private val endInclusive: Char

        init {
           checkArgument(endInclusive >= startInclusive)
            this.startInclusive = startInclusive
            this.endInclusive = endInclusive
        }

        override fun matches(c: Char): Boolean {
            return c in startInclusive..endInclusive
        }

       
         // used only from other GwtIncompatible code
        override fun setBits(table: BitSet) {
            //table[startInclusive.code] = endInclusive.code + 1
             table.set(startInclusive.code,endInclusive.code + 1)
        }

        override fun toString(): String {
            return ("CharMatcher.inRange('"
                    + showCharacter(startInclusive)
                    + "', '"
                    + showCharacter(endInclusive)
                    + "')")
        }
    }

    /** Implementation of [.forPredicate].  */
    private class ForPredicate (private val predicate: Predicate<Char>) : CharMatcher() {

        override fun matches(c: Char): Boolean {
            return predicate.test(c)
        }

        /*@Suppress("deprecation") // intentional; deprecation is for callers primarily
        override fun apply(character: Char): Boolean {
            return predicate.test(character)
        }*/

        override fun toString(): String {
            return "CharMatcher.forPredicate($predicate)"
        }
    }

    companion object {
        /*
   *           N777777777NO
   *         N7777777777777N
   *        M777777777777777N
   *        $N877777777D77777M
   *       N M77777777ONND777M
   *       MN777777777NN  D777
   *     N7ZN777777777NN ~M7778
   *    N777777777777MMNN88777N
   *    N777777777777MNZZZ7777O
   *    DZN7777O77777777777777
   *     N7OONND7777777D77777N
   *      8$M++++?N???$77777$
   *       M7++++N+M77777777N
   *        N77O777777777777$                              M
   *          DNNM$$$$777777N                              D
   *         N$N:=N$777N7777M                             NZ
   *        77Z::::N777777777                          ODZZZ
   *       77N::::::N77777777M                         NNZZZ$
   *     $777:::::::77777777MN                        ZM8ZZZZZ
   *     777M::::::Z7777777Z77                        N++ZZZZNN
   *    7777M:::::M7777777$777M                       $++IZZZZM
   *   M777$:::::N777777$M7777M                       +++++ZZZDN
   *     NN$::::::7777$$M777777N                      N+++ZZZZNZ
   *       N::::::N:7$O:77777777                      N++++ZZZZN
   *       M::::::::::::N77777777+                   +?+++++ZZZM
   *       8::::::::::::D77777777M                    O+++++ZZ
   *        ::::::::::::M777777777N                      O+?D
   *        M:::::::::::M77777777778                     77=
   *        D=::::::::::N7777777777N                    777
   *       INN===::::::=77777777777N                  I777N
   *      ?777N========N7777777777787M               N7777
   *      77777$D======N77777777777N777N?         N777777
   *     I77777$$$N7===M$$77777777$77777777$MMZ77777777N
   *      $$$$$$$$$$$NIZN$$$$$$$$$M$$7777777777777777ON
   *       M$$$$$$$$M    M$$$$$$$$N=N$$$$7777777$$$ND
   *      O77Z$$$$$$$     M$$$$$$$$MNI==$DNNNNM=~N
   *   7 :N MNN$$$$M$      $$$777$8      8D8I
   *     NMM.:7O           777777778
   *                       7777777MN
   *                       M NO .7:
   *                       M   :   M
   *                            8
   */
        // Constant matcher factory methods
        /**
         * Matches any character.
         *
         * @since 19.0 (since 1.0 as constant `ANY`)
         */
        fun any(): CharMatcher {
            return Any.INSTANCE
        }

        /**
         * Matches no characters.
         *
         * @since 19.0 (since 1.0 as constant `NONE`)
         */
        fun none(): CharMatcher {
            return None.INSTANCE
        }

        /**
         * Determines whether a character is whitespace according to the latest Unicode standard, as
         * illustrated [here](http://unicode.org/cldr/utility/list-unicodeset.jsp?a=%5Cp%7Bwhitespace%7D).
         * This is not the same definition used by other Java APIs. (See a [comparison of several definitions of "whitespace"](https://goo.gl/Y6SLWx).)
         *
         *
         * All Unicode White_Space characters are on the BMP and thus supported by this API.
         *
         *
         * **Note:** as the Unicode definition evolves, we will modify this matcher to keep it up to
         * date.
         *
         * @since 19.0 (since 1.0 as constant `WHITESPACE`)
         */
        fun whitespace(): CharMatcher {
            return Whitespace.INSTANCE
        }

        /**
         * Determines whether a character is a breaking whitespace (that is, a whitespace which can be
         * interpreted as a break between words for formatting purposes). See [.whitespace] for a
         * discussion of that term.
         *
         * @since 19.0 (since 2.0 as constant `BREAKING_WHITESPACE`)
         */
        fun breakingWhitespace(): CharMatcher {
            return BreakingWhitespace.INSTANCE
        }

        /**
         * Determines whether a character is ASCII, meaning that its code point is less than 128.
         *
         * @since 19.0 (since 1.0 as constant `ASCII`)
         */
        fun ascii(): CharMatcher {
            return Ascii.INSTANCE
        }

        /**
         * Determines whether a character is an ISO control character as specified by [ ][Char.isISOControl].
         *
         *
         * All ISO control codes are on the BMP and thus supported by this API.
         *
         * @since 19.0 (since 1.0 as constant `JAVA_ISO_CONTROL`)
         */
        fun javaIsoControl(): CharMatcher {
            return JavaIsoControl.INSTANCE
        }

        fun char(match: Char): CharMatcher {
            return Is(match)
        }

        /**
         * Returns a `char` matcher that matches any character except the BMP character specified.
         *
         *
         * To negate another `CharMatcher`, use [.negate].
         */
        fun isNot(match: Char): CharMatcher {
            return IsNot(match)
        }

        /**
         * Returns a `char` matcher that matches any BMP character present in the given character
         * sequence. Returns a bogus matcher if the sequence contains supplementary characters.
         */
        fun anyOf(sequence: CharSequence): CharMatcher {
            return when (sequence.length) {
                0 -> none()
                1 -> Is(sequence[0])
                2 -> isEither(sequence[0], sequence[1])
                else ->         // TODO(lowasser): is it potentially worth just going ahead and building a precomputed
                    // matcher?
                    AnyOf(sequence)
            }
        }

        /**
         * Returns a `char` matcher that matches any BMP character not present in the given
         * character sequence. Returns a bogus matcher if the sequence contains supplementary characters.
         */
        fun noneOf(sequence: CharSequence): CharMatcher {
            return anyOf(sequence).negate()
        }

        /**
         * Returns a `char` matcher that matches any character in a given BMP range (both endpoints
         * are inclusive). For example, to match any lowercase letter of the English alphabet, use `CharMatcher.inRange('a', 'z')`.
         *
         * @throws IllegalArgumentException if `endInclusive < startInclusive`
         */
        fun inRange(startInclusive: Char, endInclusive: Char): CharMatcher {
            return InRange(startInclusive, endInclusive)
        }

        /**
         * Returns a matcher with identical behavior to the given [Char]-based predicate, but
         * which operates on primitive `char` instances instead.
         */
        fun forPredicate(predicate: Predicate<Char>): CharMatcher {
            return if (predicate is CharMatcher) predicate else ForPredicate(predicate)
        }

        private const val DISTINCT_CHARS = Char.MAX_VALUE.code - Char.MIN_VALUE.code + 1

        /**
         * Helper method for [.precomputedInternal] that doesn't test if the negation is cheaper.
         */
       
         // SmallCharMatcher
        private fun precomputedPositive(
            totalCharacters: Int, table: BitSet, description: String
        ): CharMatcher {
            return when (totalCharacters) {
                0 -> none()
                1 -> Is(table.nextSetBit(0).toChar())
                2 -> {
                    val c1 = table.nextSetBit(0).toChar()
                    val c2 = table.nextSetBit(c1.code + 1).toChar()
                    isEither(c1, c2)
                }

                else -> if (isSmall(totalCharacters, table.length())) SmallCharMatcher.from(
                    table,
                    description
                ) else BitSetMatcher(table, description)
            }
        }

       
         // SmallCharMatcher
        private fun isSmall(totalCharacters: Int, tableLength: Int): Boolean {
            return (totalCharacters <= SmallCharMatcher.MAX_SIZE
                    && tableLength > totalCharacters * 4 * Char.SIZE_BYTES)
            // err on the side of BitSetMatcher
        }

        /**
         * Returns the Java Unicode escape sequence for the given `char`, in the form "\u12AB" where
         * "12AB" is the four hexadecimal digits representing the 16-bit code unit.
         */
        private fun showCharacter(c: Char): String {
            var c = c
            val hex = "0123456789ABCDEF"
            val tmp = charArrayOf('\\', 'u', '\u0000', '\u0000', '\u0000', '\u0000')
            for (i in 0..3) {
                tmp[5 - i] = hex[c.code and 0xF]
                c = (c.code shr 4).toChar()
            }
            return tmp.concatToString()
        }

        private fun isEither(c1: Char, c2: Char): IsEither {
            return IsEither(c1, c2)
        }
    }
}

/**
 * An immutable version of CharMatcher for smallish sets of characters that uses a hash table with
 * linear probing to check for matches.
 *
 * @author Christopher Swenson
 */
class SmallCharMatcher(
    private val table: CharArray,
    private val filter: Long,
    private val containsZero: Boolean,
    description: String
) : NamedFastMatcher(description) {
    private fun checkFilter(c: Int): Boolean {
        return 1L == 1L and (filter shr c)
    }

    override fun matches(c: Char): Boolean {
        if (c.code == 0) {
            return containsZero
        }
        if (!checkFilter(c.code)) {
            return false
        }
        val mask = table.size - 1
        val startingIndex = smear(c.code) and mask
        var index = startingIndex
        do {
            index = if (table[index].code == 0) { // Check for empty.
                return false
            } else if (table[index] == c) { // Check for match.
                return true
            } else { // Linear probing.
                index + 1 and mask
            }
            // Check to see if we wrapped around the whole table.
        } while (index != startingIndex)
        return false
    }

    override fun setBits(table: BitSet) {
        if (containsZero) {
            table.set(0)
        }
        for (c in this.table) {
            if (c.code != 0) {
                table.set(c.code)
            }
        }
    }

    companion object {
        const val MAX_SIZE = 1023
        private const val C1 = -0x3361d2af
        private const val C2 = 0x1b873593

        /*
   * This method was rewritten in Java from an intermediate step of the Murmur hash function in
   * http://code.google.com/p/smhasher/source/browse/trunk/MurmurHash3.cpp, which contained the
   * following header:
   *
   * MurmurHash3 was written by Austin Appleby, and is placed in the public domain. The author
   * hereby disclaims copyright to this source code.
   */
        fun smear(hashCode: Int): Int {
            return C2 *(hashCode * C1).rotateLeft(15)
            //return C2 * Integer.rotateLeft(hashCode * C1, 15)
        }

        // This is all essentially copied from ImmutableSet, but we have to duplicate because
        // of dependencies.
        // Represents how tightly we can pack things, as a maximum.
        private const val DESIRED_LOAD_FACTOR = 0.5

        /**
         * Returns an array size suitable for the backing array of a hash table that uses open addressing
         * with linear probing in its implementation. The returned size is the smallest power of two that
         * can hold setSize elements with the desired load factor.
         */
        fun chooseTableSize(setSize: Int): Int {
            if (setSize == 1) {
                return 2
            }
            // Correct the size for open addressing to match desired load factor.
            // Round up to the next highest power of 2.
            //var tableSize = Integer.highestOneBit(setSize - 1) shl 1
            var tableSize= (setSize - 1).takeHighestOneBit() shl 1
            while (tableSize * DESIRED_LOAD_FACTOR < setSize) {
                tableSize = tableSize shl 1
            }
            return tableSize
        }

        fun from(chars: BitSet, description: String): CharMatcher {
            // Compute the filter.
            var filter: Long = 0
            val size = chars.cardinality()
            val containsZero = chars[0]
            // Compute the hash table.
            val table = CharArray(chooseTableSize(size))
            val mask = table.size - 1
            var c = chars.nextSetBit(0)
            while (c != -1) {

                // Compute the filter at the same time.
                filter = filter or (1L shl c)
                var index = smear(c) and mask
                while (true) {
                    // Check for empty.
                    if (table[index].code == 0) {
                        table[index] = c.toChar()
                        break
                    }
                    // Linear probing.
                    index = index + 1 and mask
                }
                c = chars.nextSetBit(c + 1)
            }
            return SmallCharMatcher(table, filter, containsZero, description)
        }
    }
}

fun CharMatcher.Companion.from(chars: BitSet, description: String) = SmallCharMatcher.from(chars, description)